{%- set class_name = class_name | default('MyModule') -%}
{%- set filename = filename | default('my_module.py') -%}
{%- set module_name = module_name | default(convert_pascal_to_snake_case(class_name)) -%}
{%- set option_schema = option_schema | default([{"name": "debug", "default": False, "required": False}]) -%}
{%- set required_options = [] -%}
{%- set logging_enabled = logging_enabled | default(True) -%}
{%- set store_node = store_node | default(True) -%}
{%- set store_option = store_option | default(True) -%}
{%- set passthrough = passthrough | default(False) -%}

{%- import 'components/macros.j2' as macros -%}

{% block header -%}
"""
TODO: Add the script header information here.
Example: A custom BMF module generated by the BMF Module Template Generator.
"""
{%- endblock %}

{% block std_imports -%}
import argparse
import json
import os
import sys
{%- endblock %}

{% block bmf_imports -%}
import bmf
from bmf import (
    Module,
    Log,
    LogLevel,
    InputType,
    ProcessResult,
    Packet,
    Timestamp,
    VideoFrame,
    AudioFrame,
)
import bmf.hmp as mp
{%- endblock %}

{% block user_imports -%}
# TODO: Add dependencies including local imports and third party pip packages here.
{%- endblock %}

{% block bmf_module -%}
class {{ class_name }}(Module):
    {% block init -%}
    def __init__(self, node=None, option=None):
        {% if logging_enabled %}Log.log(LogLevel.INFO, "{{ class_name }} module option: ", option){% endif %}
        {% if store_node %}self._node = node{% endif %}
        {% if store_option %}self._option = option{% endif %}
        {% for option_info in option_schema -%}
        self._{{ option_info.name }} = option.get("{{ option_info.name }}", {{ render_primitive_value(option_info.default, 2) }})
        {%- if option_info.required %}{% do required_options.append(option_info.name) %}{% endif -%}
        {%- if not loop.last %}
        {% endif -%}
        {%- endfor %}
        {%- if required_options %}

        # Validate required options
        {% for option_name in required_options -%}
        if self._{{ option_name }} is None:
            raise ValueError("Option '{{ option_name }}' is a required but was not provided.")
        {%- if not loop.last %}
        {% endif -%}
        {%- endfor %}
        {%- endif %}
        self._version = self.get_version()
        {% block custom_init -%}
        self._eof_received = False
        
        # TODO: Add custom initialisation logic here.
        {%- endblock %}
    {%- endblock %}

    {% block process -%}
    def process(self, task):
        {% block before_process_mainloop -%}
        input_stream = task.get_inputs()[0]
        output_stream = task.get_outputs()[0]

        {% endblock %}

        {%- block process_mainloop -%}
        while not input_stream.empty():
            pkt = input_stream.get()

            {% block detect_eof -%}
            if pkt.timestamp == Timestamp.EOF:
                {% if logging_enabled -%}
                Log.log_node(LogLevel.INFO, task.get_node(), "Received EOF")
                {%- endif %}
                self._eof_received = True
                output_stream.put(Packet.generate_eof_packet())
                continue
            {%- endblock %}

            {% block process_packet -%}
            {% if passthrough -%}
            output_stream.put(pkt) # passthrough

            {% endif -%}
            # TODO: Add per-frame packet processing logic here.
            {%- endblock %}
        {%- endblock %}

        {% block handle_eof -%}
        if self._eof_received:
            # TODO: Add additional EOF processing logic here.
            task.timestamp = Timestamp.DONE
            return ProcessResult.OK
        {%- endblock %}

        {% block after_process_mainloop -%}
        return ProcessResult.OK
        {%- endblock %}
    {%- endblock %}

    {% block get_version -%}
    def get_version(self):
        return "{{ version | default('0.0.1') }}"
    {%- endblock %}
{%- endblock %}

{% block harness -%}
{% block run_graph -%}
{{ macros.run_bmf_graph(filename, class_name, module_name, required_options, has_video=True, has_audio=False) }}
{%- endblock %}

def main():
    parser = argparse.ArgumentParser(
        description='Run {{ module_name }} to process an input video file',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    
    # Register arguments
    parser.add_argument('-i', '--input', required=True, help='Path to the input file')
    parser.add_argument('-o', '--output', required=False, default="output.mp4", help='Path to the input video file')
    parser.add_argument('-c', '--config', required=False, default=None, help='Path to the BMF module options JSON file')
    parser.add_argument('--verbose', action='store_true', help='Enable verbose output')
    
    args = parser.parse_args()

    input_path = args.input
    config_path = args.config
    
    # Check the input video file exists
    if not os.path.isfile(input_path):
        print(f"Error: Video file not found: {input_path}")
        sys.exit(1)
    
    # Check the config file exists if given
    if config_path and not os.path.isfile(config_path):
        print(f"Error: Config file not found: {config_path}")
        sys.exit(1)

    # Check video file extension (basic validation)
    valid_video_extensions = ['.mp4', '.avi', '.mov', '.mkv']
    if not any(input_path.lower().endswith(ext) for ext in valid_video_extensions):
        print(f"Warning: File {input_path} may not be a valid video file.")
    
    # Load config
    if config_path:
        try:
            with open(config_path, 'r') as f:
                config = json.load(f)
        except json.JSONDecodeError:
            print(f"Error: Config file is not a valid JSON: {config_path}")
            sys.exit(1)
    else:
        config = {}
    
    # Process the video according to the configuration
    output_path = args.output
    verbose = args.verbose
    
    if verbose:
        print(f"Processing video: {input_path}")
        print(f"Using configuration: {json.dumps(config, indent=2)}")
        print(f"Output will be saved to: {output_path}")
    
    run_bmf_graph(
        input_path,
        output_path,
        config,
    )
    
    print(f"Video processing complete. Output saved to {output_path}")

if __name__ == "__main__":
    main()
{%- endblock %}